设计模式(十六)—— 解释器模式
模式简介
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
顾名思义,解释器模式就是定义一种语法,并提供一个解释器,客户端可以使用该解释器来解释这个语句来解决问题。例如写文档常用的Markdown语法,可以用-来表示无序列表,用---来表示下划线。通过解释器模式对这种经常使用到的事物,将其定义为一个简单的标识,以便于我们使用。
结构分析
UML类图
角色说明
- AbstractExpression
抽象表达式类,包含一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
- TerminalExpression
末端表达式类,实现与在语法中终结符相关联的解释操作,在语句中每个终结符都需要这个实例。
- NonterminalExpression
非末端表达式类,实现在语法中非末端表达式的解释操作。通常递归的自我调用。
- Context
上下文,包含解释器之外的一些全局信息。
结构代码
//上下文类
public class Context
{
}
//抽象表达式类
abstract class AbstractExpression
{
public abstract void Interpret(Context context);
}
//末端表达式类
class TerminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("Called Terminal.Interpret()");
}
}
//非末端表达式类
class NonterminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("Called Nonterminal.Interpret()");
}
}
//客户端调用
class Program
{
static void Main(string[] args)
{
Context context = new Context();
var list = new List<AbstractExpression>();
list.Add(new TerminalExpression());
list.Add(new NonterminalExpression());
list.Add(new TerminalExpression());
list.Add(new TerminalExpression());
foreach (var exp in list)
{
exp.Interpret(context);
}
Console.ReadLine();
}
}
示例分析
本节我们通过解释器模式实现一个简易的Markdown语法,在控制台中输出解释后的内容。首先创建上下文类Context,包含一个Content成员。
class Context
{
public string Content { get; set; }
}
定义IExpression接口,并通过UnOrderedListExpression和UnderlineExpression子类分别实现无序列表解释器以及下划线解释器。
interface IExpression
{
void Interpret(Context context);
}
class UnOrderedListExpression : IExpression
{
public void Interpret(Context context)
{
if (context.Content.Contains("- "))
{
context.Content = context.Content.Replace("- ", "·");
}
}
}
class UnderlineExpression : IExpression
{
public void Interpret(Context context)
{
if (context.Content.Contains("---"))
{
context.Content = context.Content.Replace("---", "__________________________");
}
}
}
客户端调用,先向上下文实例的content属性给定内容,并使用UnOrderedListExpression和UnderlineExpression解释器分别对其进行解释,最后输出结果。
class Program
{
static void Main(string[] args)
{
Context context = new Context();
context.Content = "- apple\r\n";
context.Content += "- orange\r\n";
context.Content += "- banana\r\n";
context.Content += "---";
List<IExpression> tree = new List<IExpression>();
tree.Add(new UnOrderedListExpression());
tree.Add(new UnderlineExpression());
foreach (var exp in tree)
{
exp.Interpret(context);
}
Console.WriteLine(context.Content);
Console.ReadLine();
}
}
程序输出:
使用场景
-
为一些重复出现的问题定义一组简单的语法,便于使用
-
一个语言需要解释,并将该语言中的句子表示为一个抽象语法树
优点和不足
优点
- 易于改变和扩展语法
因为使用类来声明表达式,可以使用继承来修改或改变该表达式的行为。
- 易于实现新的解释表达式方法
不足
- 容易引起类“爆炸”
- 对于复杂的语法较难维护